/**
 * @fileOverview This file defined tmBoxWindow and mapBoxWindow classes.
 * @author Jeff C Huang
 */
 /**
 * This class extends from boxWindow, can be used for creating basic widgets.
 * Add a IncludeJavaScript function in $WP_HOME/js/common.js for loading 
 * this js file before using it.
 * @class 
 * @constructor
 * @extends boxWindow
 */
var tmBoxWindow = new Class(
/** @lends tmBoxWindow */
{
	Extends:boxWindow,
    /**
     * General widget options can be modified here.
     * @type Object
     */
    widgetModule: 'modTM',   // This is only default parameter, usually widgets has their owns     
    
    /**
     * The options object of one widget.
     * @type Object
     * @example 
     * options: {
     *   BtnRefresh: true,   // If we want to show the refresh button
     *   BtnMin: true,       // If want to show the minimize button
     *   BtnSettings: false, // If we want to show the settings button
     *   uniqueCss: false,   // Unique css name for this widget 
     *   modal: false        // Determine if this widget is a modal window
     * },
     */
    options: {
        BtnRefresh: true,   
        BtnMin: true,       
        BtnSettings: false, 
        uniqueCss: false,   
        modal: false
    },
    div_id: null,           // the ID of content block 
    settingsBox: null,      // reference of settingBox
    widgetSetting: null,    // reference of modal setting box
    hasDrawed: false, 
    //widget need to update this value to true if has finished first time drawed
    isShowingSetting: false,
    ChartTimer: null,
    checkSeconds: 1,
    reportserver: [],
    currentscanservercount: 0,
    currentscanserver: null,
    scanservercheckarray: new Array(),
    strdscanserverarray: new Array(),
    callbackreadyarray: new Array(),
    errormessageHash: new Hash(),
    _tmpServerList: [],
    
    /** Turn it as true while debug */
    DEBUG: false, 
    /** Turn it as true while debug Flash charts related */
    DEBUG_CHART: false,
    
    /** If want to use zebra table rows */
    zebraTable: true,
    
    /** 
     * If this widget has table view, the is the data format of table rows, 
     * @example 
     * formatTableRows: [
     *   // type    : The type of column content (text||number}
     *   // xmlAttr : The displayed text will map to defined attribute of XML node
     *   // link    : Set the XML attribute to map if has a link on it
     *   {type:'text',   xmlAttr:'label'},
     *   {type:'number', xmlAttr:'value'},
     *   {type:'text',   xmlAttr:'percent', link:'link'}
     * ],
     */
    formatTableRows: [],
    
    /** Language resource object of one widget */
    widgetResourceObj:{},
    
    /**
     * This will create widget setting by calling these functions. <br>
     * These functions should return HTML string, then they will be exucuted in order.<br>
     * In the default, it will be called in order :
     * @example 
     * html = this.MakeTitleSetting() + 
     *        this.MakeSettingButtons() ;
     * // The returned HTML should follow this default layout:
     * // (3 TDs in one TR)
     * <tr>
     *   <td>Setting Name</td><td>Form Element</td><td>Form Element 2</td>
     * </tr>
     * // or: (2 TD in one TR)
     * <tr>
     *   <td>Setting Name</td><td colspan="2">Form Element</td>
     * </tr>
     * 
     * @type Array
     */
    settingCall: ['MakeTitleSetting', 'MakeSettingButtons'],
    
    /** Be used in this.MakeDateRange(), 
     * 1 || 7 || 14 || 30, indicates as today, 1 week, 2 weeks, 1 month 
     */
    recentdays: 1, 
    /** Date range possible value: [1,7,14,30] */
    date_range: [1,7,14,30],
    hasDateRange: false,
    
    /** Be used in this.MakeTitleMenu()
     * groupview = 1 || 2, used for title menu component
     */
    groupview:1,  
    groupData : {},
    
    /** 
     * The view type of fushion chart.
     * @type Number
     */
    fushionview:1, 
    /**
     * The data set of this.fushionview, be used in this.MakeViewControl() 
     * The possible value are 'pie_chart', 'bar_chart', 'line_chart', and 'tabulaar'
     * Also be used for L10N and CSS class name, matched the value of fushionview.
     * @type Object
     */
    viewData : {},
    
    /**
     * Default widget setting, should be defined in widget/module.js <br>
     * The default data if it's a newly added widget, 
     * shoule includ all possible settings of this widget
     * @example
     * defaultSetting: '{recentdays:1, fushionview:1, groupview:1, title:"", mysetting:""}',
     * @type String 
     */
    defaultSetting: '',
    
    /** If want to display the last check time */
    hasLastCheckTime: true,
    
    // help window
    helppagedialog:null,
    
    // The array of sotable columns, ['OnlineNumber', '', 'OfflineNumber'] means there are 3 columns total
    sortColumns: [],        
    // Indicate current soring column, the array index of this.sortColumns, -1 means no sorting 
    currentSort: -1,        
    // Indicate current sorting method: ASC || DESC
    currentSortType: 'DESC', 
    /** Icons of sorting 
     * @type Object
     * @config {String} [DESC] The url of DESC icon
     * @config {String} [ASC] The url of ASC icon
     */
    sortIcon: 
    {
        'DESC':'<img src="'+WP_WEBROOT_NO_SLASH+'/widgetBase/modBaseWidget/img/arrow_down_blk.gif" />',
        'ASC' :'<img src="'+WP_WEBROOT_NO_SLASH+'/widgetBase/modBaseWidget/img/arrow_up_blk.gif" />'
    },
    
    /**
     * Setting of flash chart, please see http://www.fusioncharts.com/docs/
     * @see <a href="http://www.fusioncharts.com/docs/">http://www.fusioncharts.com/docs/</a>.
     */
    flashSetting: {
        showBorder: '0',
        bgColor   : 'FFFFFF'
    },
    
    /**
     * Initialize a widget with basic settings
     * @param {Number} position Number of column
     * @param {Number} id Number of widget id
     * @param {Boolean} showMin If showing minimize button
     * @param {Boolean} showClose If showing close button
     * @param {Boolean} showSetting If showing setting button
     * @param {Boolean} showHelp If showing help button
     * @param {Boolean} allowDrag If this widget allows drag & drop
     * @param {Boolean} uniqueCss If this widget has unique CSS class name
     */
    initialize: function(position,id,showMin,showClose,showSetting,showHelp,allowDrag,uniqueCss,pageNumber,order,widget_key) {
        // set language resource object
        window[this.options.widgetname+'_locLang'] = new localLang(this.options.name);
        modList.set(this.options.name, window[this.options.widgetname+'_locLang'].label('title'));
        
        if (id) {
            this.myid = id;
        } else {
            this.myid = pc;
            pc++;
        }
        //SET THE NEW VARIABLES HERE. IT IS USED IN window.js	-- NO NEED TO EDIT/ADD ANYTHING THERE. 
        if ($defined(showMin)) this.options.BtnMin = showMin;
        if ($defined(showClose)) this.options.BtnClose = showClose;
        if ($defined(showSetting)) this.options.BtnSettings = showSetting;
        if ($defined(showHelp)) this.options.BtnHelp= $defined(showHelp) ? showHelp: true;	
        if ($defined(allowDrag)) this.options.draggable = allowDrag;
        if ($defined(uniqueCss)) this.options.uniqueCss = uniqueCss;
        
        this.parent(position,id,showMin,showClose,showSetting,showHelp,allowDrag,uniqueCss,pageNumber,order,widget_key);
    },
    
    /**
     * This function will be called for making specific content once the basic frame of widget is ready, 
     * each widget needs to write its own onFinish
     */
    onFinish: function()
    {
        // get the widget width by current browser window size
        this.contentwidth = wfc_getCurrentColumnWidth(this) - 4;
        
        // set language resource
        this.widgetResourceObj = window[this.options.widgetname+'_locLang'];
        
        // set title in this.options
        this.options.title = this.widgetResourceObj.label('title');
        
        // set this widget box ID
        this.div_id = 'div_id' + this.myid;
        
        // parse saved settings of on widget
        this.ParseSavedSettings();
        
        // make common content of one widget
        this.MakeContentBlock();
        
        // fill the title of one widget
        this.fillTitle(this.options.title); 
        
        // make date range
        if(this.hasDateRange) {
            this.MakeDateRange();
        }
        
        // groupview
        this.MakeTitleMenu(this.groupData);
        
        // fushion view 
        this.MakeViewControl();
        
        // call onRendered which should be defined in module.js
        this.onRendered();
        
        this.ShowWidget();	
    },
    
    /** You may define this function in module.js  */
    onRendered: function()
    {
        
    },
    
    /**
     * Called in onFinish, to parse the value of widget settings from JSON
     */
    ParseSavedSettings: function() 
    {
        // get the saved settings full string
        var savedSettings = JSON.decode(this.getData(this.myid)||this.defaultSetting); 
        // debug
        if(this.DEBUG) { this.PrintVar(savedSettings,'ParseSavedSettings()-> Saved settings');}
        // get default widget settings
        var defaultSetting = JSON.decode(this.defaultSetting);
        $each(defaultSetting, function(v, k) {
            if(k=='title') {
                this.options.title = savedSettings.title ?  savedSettings.title : this.options.title;
            }
            this[k] = savedSettings[k];
        }.bind(this));
    },
    
    /**
     * To show the help content of this widget. The help content should be
     * a HTML file and located in: <br>
     * i.e. for 2 languages English and Japanese <br>
     *  WP_HOME/widget/modMyWidget/help/en_US/help.html <br>
     *  WP_HOME/widget/modMyWidget/help/ja_JP/help.html <br>
     */
    showHelpPage : function () {
        this.helppagedialog=wfc_show_help_page(this);
        this.helppagedialog.fillTitle(this.options.title);    	
    },
       
    /**
     * Create a box of date range picker with a dorpdown menu.
     * @param {HTMLObject} parent The parent contains this box
     */
    MakeDateRange: function (parent) {
        if(this.dateBox) {
            this.dateBox.destroy();
        }
        
        this.dateBox = new Element('div', {
            'class'    : 'scope_box'
        }).inject(parent||this.dataViewBox, 'before');
        
        this.dateBox.setHTML(this.makePeriod());
        
        var sel = $('period_'+ this.myid);
        
        // remove event
        if (sel) {
            // selected time
            sel.value = this.recentdays;
            sel.removeEvents();
            // set up event
            sel.addEvent('change', function() 
            {
                this.recentdays = sel.value;
                this.saveSettings();
            }.bind(this));
        }
    },
    
    /**
     * Make credential settings for proxy server
     */
    MakeCredentialSetting: function()
    {
        this.settingsBox.addEvent('onSettingDone', function() {
            var link = $('credential_setting_'+this.myid);
            if(!link) return ;
            
            link.addEvent('click', function(e){
                e.preventDefault();
                if(custom_options.use_modal_widget_setting)
                {
                    this.widgetSetting.closeModal();
                }
                server_list();
            }.bind(this));
        }.bind(this));
        
        var label_h = 'Credential Settings';
        var label = 'Set Credential';
        return '<tr><td>'+ label_h +'</td><td colspan="2"><a href="javascript:void(0);" id="credential_setting_'+this.myid+'">'+ label +'</a></td></tr>';
    },
    
    /**
     * To make a save button and a cancel button in setting box. 
     * @param {Function} beforeSaveEvent (Optional) A event function before saving settings
     * @param {Function} beforeCancelEvent (Optional) A event function before cancel settings
     */
    MakeSettingButtons: function(beforeSaveEvent,beforeCancelEvent) 
    {
        // save button
        this.settingsBox.addEvent('onSettingDone', function() {
            //var save_btn = $('setting_save_'+this.myid);
            var save_btn =this.settingsBox.getElement("input[name=save]");
            if(save_btn) {
                save_btn.removeEvents('click');
                save_btn.addEvent('click', function() {
                    if($defined(beforeSaveEvent)){
                        beforeSaveEvent.bind(this)();
                    }
                    this.saveSettings();
                }.bind(this));
            }
            
            // close button
            //var close_btn = $('setting_cancel_'+this.myid);
            var close_btn = this.settingsBox.getElement("input[name=cancel]");
            if(close_btn) {
                close_btn.removeEvents('click');
                close_btn.addEvent('click', function(e) {
                     e.preventDefault(e);
                     if($defined(beforeCancelEvent)){
                        beforeCancelEvent.bind(this)();
                     }
                     // if modal setting
                     if(custom_options.use_modal_widget_setting) {
                        this.widgetSetting.closeModal();		
                     } else {
                        $(this.BtnEditID).fireEvent('click');
                     }
                }.bind(this));
            }
        }.bind(this));
        
        var Lang = lang;
        var html = [];
        html.push(
            '<tr><td colspan="3"><input class="button" type="button"  id="setting_save_',this.myid,'"  value="', 
                Lang.label('btn_save'), '" name="save" />',
            '<input class="button" type="button"  id="setting_cancel_',this.myid,'"  value="',
                Lang.label('btn_cancel'), '" name="cancel" /></td></tr>'
        );
        return html.join('');
    },
    
    /**
     * Generate html of selectable title menu (like dropdown menu), while user selected a title, 
     * the widget will save the value of selected title.
     * @param {Object} data The key/value pairs for text/value of each option
     * @param {Function}   func     (Optional) The event function before saving setting 
     * @param {HTMLObject} parent   (Optional) The parent which title menu append to, default is this.dataViewBox
     * @param {String}     position (Optional) The position to insert this title menu 
     */
    MakeTitleMenu: function(data, func, parent, position)
    {
         var len = $H(data).getLength();
        if(len<1) return ;
        
        this.titleMenu = new Element('div', { 'class':'selectable_link'} ).inject( parent||this.dataViewBox, 
            parent ? (position||'bottom'):'before');
        var selected = new Element('a', 
                { 'href':'#', 'id':'selectable_link_'+this.myid, 'class':'group_link'}
            ).injectInside(this.titleMenu);
        var link_list = new Element('p',{'style':'display:none;'}).injectInside(this.titleMenu);
        var max_w = 0;
        var padding = 0;
        $each(data, function(text, gv) {
            var link = new Element('a', {'hef':'#'+text, 'groupview':gv} ).setHTML(text).injectInside(link_list);
            if(this.groupview == parseInt(gv, 10)) {
                selected.setHTML(text);
            }
            if(!padding) {
                padding = parseInt(link.getStyle('padding-left'),10) + parseInt(link.getStyle('padding-right'),10);
            }
        }.bind(this));
        
        // event of changing group view
        link_list.addEvent('click', function(e) {
            e.preventDefault();
            var link = e.target;
            var new_value = parseInt(link.getAttribute('groupview'),10);
            link_list.setStyle('display', link_list.getStyle('display')=='none' ? '':'none');
            
            if(this.groupview == new_value) return ;
            if($defined(func)) {
                func.bind(this)();
            }
            link.blur();
            selected.setHTML(link.innerHTML);
            this.groupview = new_value;
            this.saveSettings();
        }.bind(this));
                
        // event for clicking selected one (nothing happen)
        selected.addEvent('click', function(e) {
            link_list.setStyle('display', link_list.getStyle('display')=='none' ? '':'none');
            e.preventDefault();
            selected.blur();
            
            // adjust the width of each link
            if(!max_w) {
                var links = link_list.getElements('a');
                $each(links, function(l) {
                    max_w = Math.max(max_w, l.getSize().x);
                });
                max_w = max_w - padding;
                $each(links, function(l) {
                    l.setStyle('width', max_w+'px');
                });
            }
        }.bind(this));
        
        // event for while mouse leaves the menu, should close the select list
        this.titleMenu.addEvent('mouseout', function(e) {
            var tar = e.relatedTarget;
            this.isLeaving = true;
            while(tar) {
                if(tar.tagName=='BODY') { 
                    break; 
                }
                else if(tar==this.titleMenu) {
                    this.isLeaving = false;
                    break;
                }
                tar = tar.parentNode;
            }
            
            if(this.leavingTriggered) return ;
            this.leavingTriggered = true;
            
            (function() {
                if(this.isLeaving) link_list.setStyle('display','none');
                this.leavingTriggered = false;
            }).delay(1000, this);
        }.bind(this));
        
        this.titleMenu.addEvent('mouseover', function(e) {
            this.isLeaving = false;
        }.bind(this));
    },
    
    /**
     * The view controller to swicth between pie, bar, line, and table view
     * @param {Function}   func     (Optional) The event function before saving setting 
     * @param {HTMLObject} parent   (Optional) The parent which title menu append to, default is this.dataViewBox
     * @param {String}     position (Optional) The position to insert this view control 
     */
    MakeViewControl: function(func, parent, position) 
    {
        var len = $H(this.viewData).getLength();
        if(len<1) return ;
        
        this.viewBox = new Element('div', {'class':'view_control'}).inject( parent||this.dataViewBox, 
            parent ? (position||'bottom'):'before');
        
        this.viewBox.addEvent('click',function(e) 
        { // click event
            e.preventDefault();
            e.target.blur();
            
            // to prevent duplicated clicking
            if(this.isAjaxing) return ;
            
            // if clicking on other places
            if(e.target.nodeName!='A') return ;
            
            var cur = e.target;
            var new_value = parseInt(cur.getAttribute('fushionview'), 10);
            
            if(new_value == this.fushionview) return ;
            
            // the event before save if any
            if($defined(func)){
                func.bind(this)();
            }
            
            var cls = 'selected';
            $each( this.viewBox.getChildren(), function(v) {
                if(v != cur && v.hasClass(cls)) {
                    v.removeClass(cls)
                } else if(v ==cur && !v.hasClass(cls)) {
                    v.addClass(cls)
                }
            });
            this.fushionview = new_value;
            this.isAjaxing = true;
            this.saveSettings();
        }.bind(this));
        
        // set HTML
        var elements = [];
        elements.push(new Element('span').setHTML(TM_Lang.label('views')));
        // view_type = {id:1, name:'pie_chart', swf:''}
        $each( this.viewData, function(view_type, i) {
            var el = new Element('a', 
                {'href':'#', 'class':view_type.name, 'title':TM_Lang.label(view_type.name), 'fushionview':i});
            if(this.fushionview == parseInt(i, 10)) {
                el.addClass('selected');
            }
            elements.push(el);
        }.bind(this));
        // due to the float CSS, it's necessary to revewse the order
        elements = elements.reverse();
        $each( elements, function (v) { 
            v.injectInside(this.viewBox);
        }.bind(this));
    },
    
    ClearCharts: function()
    {
        if(!this.contentBlock) return ;
        var parent = this.dataViewBox;
        // delete charts
        while(parent.getFirst()) {
            var child = parent.getFirst();
            if(child.tagName!='TABLE')  {
                parent.empty();
            }
            else return;
        }
        return ;
    },
    
    // extract table when this.fushionview is table
    MakeTable: function()
    {
        var parent = this.dataViewBox;
        
        // these 2 methods should be defined
        if(!this.MakeCloumnHead) return ;
        if(!this.GetAllRows) return ;
        
        var table = parent.getElement('table') || 
                    new Element('table').injectInside(parent).addClass('datagrid').setProperties({'cellspacing':0,'cellpadding':0});
        var thead = parent.getElement('thead') || this.MakeCloumnHead.bind(this)(table);
        var tbody = parent.getElement('tbody') ;
        if(tbody) { tbody.destroy()} // delete previous results
        
        var tbody = new Element('tbody').injectInside(table);
        var data = initXMLDOM(this.strXML);
        // get all pieces of table data
        var clone = this.GetAllRows(data)
        
        if(!clone) return ;
        var new_tb = document.createElement('tbody');
        
        if(clone.childNodes.length>0) {
            new_tb.appendChild(clone);
        } else { // no data
            var tr = document.createElement('tr');
            var cols = thead.getElementsByTagName('th').length;
            var td = addCell(tr, TM_Lang.label('no_data'), {colspan:cols, style:'text-align:center;'} );
            new_tb.appendChild(tr)
        }
        
        table.appendChild(new_tb);
        this.InitSorting(table);
    },
    
    MakeCloumnHead: function(table)
    {
        if(this.AddThead) { return this.AddThead(table);}
        
        var thead = new Element('thead').injectInside(table);
        var row = thead.insertRow(thead.rows.length);
        var tm_lang = TM_Lang;
        var html = '';
        $each(this.columnHead, function(k) {
            var label = tm_lang.label(k);
            // if not exist in tm_lang
            if(label == k) { 
                label = this.widgetResourceObj.label(k);
            }
            html += '<th title="' +label+ '">' + label + '</th>';
        }.bind(this));
        
        $(row).setHTML(html);
        return thead;
    },
    
    GetAllRows: function(data) 
    { 
        var clone = document.createDocumentFragment();
        if(this.formatTableRows.length<1) {
            this.MakeRows(data);
        }
        var sets = data.getElementsByTagName('set');
        var len = sets.length-1;
        var rowSettings = this.formatTableRows;
        for(var i = 0; i<=len; i++) {
            var tr = clone.appendChild(document.createElement('tr'));
            var set = sets[i];
            if(i%2==1 && this.zebraTable) $(tr).addClass('even');
            $each(rowSettings, function(format) {
                var text = set.getAttribute(format.xmlAttr);
                var url = format.link ? set.getAttribute(format.link) : '';
                if(format.type=='number') {
                    text = parseInt(text,10);
                    url = text > 0 ? url : '';
                }
                
                var content = url&&url!=''? '<a href="'+url+'">'+text+'</a>' : text ;
                
                addCell(tr, ''+content, {title:text} );
            }.bind(this));
        }
        return clone;
    },
    
    // initial sorting columns
    InitSorting: function(table) {
        var cols = this.sortColumns;
        var ths = table.getElements('th');
        var i = ths.length;
        
        while(i--) {
            var col = cols[i];
            var th = ths[i];
            if(col && th) {
                if(i===this.currentSort) {
                    th.addClass(this.currentSortType);
                }
                var label = th.get('text');
                //th.set('html',  label + this.sortIcon[this.currentSortType])
                th.set('html',  '<span>'+ label +'</span>')
                th.setAttribute('sortindex', i+''); 
                th.addClass('sortable');
                th.addEvent('click', this.MakeSorting.bind(this));
            }
        }
    },
    
    CalculateSortIndex: function(data)
    {
        return (data!=0 && !data) ? this.currentSort : data;
    },
    
    CalculateSortType: function(data)
    {
        return (!data) ? this.defaultSortType : data;
    },
    
    MakeSorting: function(e) {
        var th = $(e.target);
        if(th.get('tag')!='th') { 
            th = th.getParent('th'); 
        }
        
        var sortindex = parseInt(th.getAttribute('sortindex'),10);
        if(sortindex<0) return ;
        
        if(this.currentSort==sortindex) { // click on the same column
            this.currentSortType = (this.currentSortType=='DESC') ? 'ASC':'DESC';
        } else { // click on another column
            this.currentSortType = 'DESC';
            this.currentSort = sortindex;
        }
        
        this.saveSettings();
    },
    
    ResizeElements: function() {
        this.contentwidth = wfc_getCurrentColumnWidth(this) - 4;
    },

    displaySettings: function() {
        this.settingMessageOption = {
            type:'error', 
            position:'before', 
            addTo: this.settingsBox.getElement('table.server_setting')
        };
        this.settingsBox.setStyle('display', 'block');
        this.isShowingSetting = false;
    },

    generateErrorMessage: function(message, key, value, widget, widgetResourceObj) {
        switch (parseInt(key)) {
        case 410:
        case 411:
        case 412:
        case 413:
        case 414:
        case 415:
        case 416:
        case 420:
        case 421:
        case 422:
        case 430:
        case 431:
        case 441:

            message += lang.label("errorcode_" + key) + ":<BR>";
            for (var i = 0; i < value.length; i++) {
                message += "<div class='ServerNameorIPWrap' title='" + value[i] + "' style='width:" + (this.contentwidth - 150) + "'>" + "- " + value[i] + "</div>";
            }
            break;

        case wfc_timeout_errorcode:

            message += widgetResourceObj.label(widget+"_timeout_connect") + ":<BR>";
            for (var i = 0; i < value.length; i++) {
                message += "<div class='ServerNameorIPWrap' title='" + value[i] + "' style='width:" + (this.contentwidth - 150) + "'>" + "- " + value[i] + "</div>";
            }
            break;

        case wfc_failure_errorcode:

            message += widgetResourceObj.label(widget+"_failure_connect") + ":<BR>";
            for (var i = 0; i < value.length; i++) {
                message += "<div class='ServerNameorIPWrap' title='" + value[i] + "' style='width:" + (this.contentwidth - 150) + "'>" + "- " + value[i] + "</div>";
            }
            break;

        default:
            message += lang.label("errorcode_undefined") + ":<BR>";
        }
        return message;
    },

    dialogcancel: function() {
        $clear(this.ChartTimer);
        if ($chk(this.scanservercheckarray)) {
            $each(this.scanservercheckarray, function(item, key) {
                item.cancel();
            });
        }
        if (!custom_options.use_modal_widget_setting && this.settingsBox.getStyle('display') != 'none') {
            $clear(this.ConnectionStatusTimer);
            if ($chk(this.checkConnectionStatusarray)) {
                $each(this.checkConnectionStatusarray, function(item, key) {
                    item.cancel();
                });
            }
        }
        
    },
    
    UpdateDate: function(data) 
    {
        if(!this.hasDateRange) return ;
        var utc = data.getElementsByTagName('UTC');
        if(!utc) return ;
        utc = utc[0];
        if(utc) 
        {
            utc = utc.firstChild;
            var date_str = '';
            while(!date_str) {
                if(utc.nodeType==1) {
                    date_str = utc.getAttribute('utctime');
                    break;
                }
                if(!utc.nextSibling) { break;}
                utc = utc.nextSibling;
            }
            this.utc = this.setServerDate(date_str);
        }
    },
        
    setServerDate: function (date_str) 
    {
        // server date object
        // ex: '2009-10-14T03:43+08:00'
        var stamp = new Date(
            parseInt(date_str.substr(0,4)),  // year
            parseInt(date_str.substr(5,2),10)-1, // month
            parseInt(date_str.substr(8, 2)), // days
            parseInt(date_str.substr(11,2)), // hours
            parseInt(date_str.substr(14,2)) // minutes
        ) ;   
        var expdate = stamp.getTime();
        if(date_str.substr(16,1) == "+")
        {
            expdate = expdate + parseInt(date_str.substr(17,2),10)*3600*1000 + parseInt(date_str.substr(20,2),10)*60*1000;
        }
        else
        {
            expdate = expdate - parseInt(date_str.substr(17,2),10)*3600*1000 - parseInt(date_str.substr(20,2),10)*60*1000; 
        }
        stamp.setTime(expdate);
			
        // update date range
        var range = this.dateBox.getElement('span.date_range');
        var format_str = TM_Lang.label('periodformat');
        if(this.recentdays==1) 
        {
            range.setHTML(stamp.formatDate(format_str));
        }
        else
        {
            range.setHTML(
                new Date(stamp.getTime()-(parseInt(this.recentdays,10)*24*60*60*1000)).formatDate(format_str) +' ~ '+ 
                stamp.formatDate(format_str)
            );
        }
        
        return stamp;
    },
    
    GetDateByStr: function(date_str, format_str)
    {
       // server date object
        // ex: '2009-10-14T03:43+08:00'
        	
			var stamp = new Date(
      					     parseInt(date_str.substr(0,4)),  // year
                     parseInt(date_str.substr(5,2),10)-1, // month
                     parseInt(date_str.substr(8, 2)), // days
	             			 parseInt(date_str.substr(11,2)), // hours
        	     			 parseInt(date_str.substr(14,2)) // minutes
        					) ;   
			var expdate = stamp.getTime();
			if(date_str.substr(16,1) == "+")
			{
				expdate = expdate + parseInt(date_str.substr(17,2),10)*3600*1000 + parseInt(date_str.substr(20,2),10)*60*1000;
			}
			else
			{
				expdate = expdate - parseInt(date_str.substr(17,2),10)*3600*1000 - parseInt(date_str.substr(20,2),10)*60*1000; 
      }
			stamp.setTime(expdate);
      var format = format_str||TM_Lang.label('dateformat'); //MM-dd-yyyy HH:mm t
      var d = stamp.formatDate(format);       
      return d;
    },
    
    MakeTitleSetting: function()
    {
        // set up events 
        var html = [];
        
        //var title_value = htmlentities(this.options.title);
        var title_value = this.options.title;
        
        // return the HTML
        html.push(
            '<tr><td width="10%">', lang.label('inp_title') ,'</td><td colspan="2"><input type="text" name="widget_title" id="widget_title_', this.myid, '" value="', title_value, '" size="30" /></td></tr>'
        );
        return html.join('');
    },
    
    /**
     * Extract last check time.
     * this.xmlData and this.lastCheckBox have to be ready 
     */
    LastCheckTime: function()
    {
        if(!this.hasLastCheckTime) return ;
        var xml = this.xmlData;
        if(!xml) return ;
        var utc_tag = xml.getElementsByTagName('UTC');
        if(utc_tag.length==0) return ;
        
        var utc = utc_tag[0].firstChild;
        var date_str = '';
        var LANG = TM_Lang;
        while(!date_str) {
            if(utc.nodeType==1) {
                date_str = utc.getAttribute('utctime');
                break;
            }
            if(!utc.nextSibling) { break;}
            utc = utc.nextSibling;
        }
        
        var d = this.GetDateByStr(date_str, LANG.label('dateformat'));
        
        this.lastCheckBox.setHTML(LANG.label('last_check')+d);
    },

    makePeriod: function() 
    {
        var s = new StringBuffer();
        var LANG = TM_Lang;
        // date period content
        s.append( '<span class="date_select">'+LANG.label('date'));
        s.append( '<select name="period" id="period_'+this.myid+'">');
        var len = this.date_range.length-1;
        for(var i=0; i<=len; i++){
            var d = this.date_range[i];
            s.append('<option value="'+d+'">'+ LANG.label('date_'+d) +'</option>');
        }
        s.append('</select></span>');
        
        // date text
        s.append( '<span class="date_range"></span>');    
        
        return s.toString();
    },

    updateErrorMessageHash: function(ajaxobject, errorcode) 
    {
        var entryvalue = this.errormessageHash.get(errorcode);
        if (entryvalue) {
            entryvalue.push(((this.strdscanserverarray[ajaxobject.options.parameter] == "localhost") ? TM_Lang.label("localhost") : this.strdscanserverarray[ajaxobject.options.parameter]));
            this.errormessageHash.set(errorcode, entryvalue);
        }
        else {
            var errorcodedata = new Array();
            errorcodedata.push(((this.strdscanserverarray[ajaxobject.options.parameter] == "localhost") ? TM_Lang.label("localhost") : this.strdscanserverarray[ajaxobject.options.parameter]));
            this.errormessageHash.set(errorcode, errorcodedata);
        }
    },

    refreshMod: function() {
        this.dialogcancel();
        if (this.messageBox) {
            Element.remove(this.messageBox);
            this.messageBox = null;
        }
        
        this.ShowWidget();
    },

    showSettings: function() { 
        this.boxObject.removeEvents('BeforeWidgetModalSettingClose');       		
        this.boxObject.removeEvents('AfterWidgetModalSettingFinish');       		
        this.boxObject.addEvent('BeforeWidgetModalSettingClose', this.BeforeWidgetModalSettingClose.bind(this) );
        this.boxObject.addEvent('AfterWidgetModalSettingFinish', this.AfterWidgetModalSettingFinish.bind(this) );
        if( custom_options.use_modal_widget_setting && !$('setting_save_'+this.myid) ) {
            this.MakeCMSettings();
        }
        this.widgetSetting = wfc_widget_setting(this,this.settingsBox,this.OriginalshowSettings.bind(this));
        this.widgetSetting.fillTitle(this.options.title); 
    },
    
    BeforeWidgetModalSettingClose: function(){
    	this.settingsBox.removeEvents('onSettingDone');
    },
    
    AfterWidgetModalSettingFinish: function(){ 
    	this.settingsBox.fireEvent('onSettingDone');
    },
    
    OriginalshowSettings: function (){
    	   // opening settings
        if (this.settingsBox.getStyle('display') == 'none') {
            this.MakeCMSettings();
            
            // resize widget height
            var new_h = this.settingsBox.getSize().y;
            var org_h = this.contentBox.getSize().y;
            this.contentBox.setStyle('height', org_h + new_h + 'px');
            
            return ;
        }
        
        this.settingsBox.destroy();
        
        // closing settings
        // resize widget height
        var org_h = this.contentBlock.getSize().y;
        this.contentBox.setStyle('height', org_h + 'px');
        
        //this.settingsBox.setStyle('display', 'none');
        var grid = this.settingsBox.getElement('table');
        this.settingsBox = new Element('div', {'class':'window_setting', id:'hmain_settings'+this.myid}).inject(this.contentBox, 'top');
    },
    
    MakeCMSettings: function()
    {   
        var html = [];
        
        html.push('<table cellspacing="0" cellpadding="3" class="grid">');
        
        $each(this.settingCall, function(method) {
            if($type(this[method])=='function') {
                html.push(this[method]());
            }
        }.bind(this));
        
        html.push('</table>');
        
        this.settingsBox.set('html', html.join('')).setStyle('display','block'); 
    },
        
    saveSettings: function() {
        // loading message
        var tm_lang = TM_Lang;
        this.SetLoadingText(tm_lang.label('acquiring_data'));
        
        // check user inputed title
        var title = $('widget_title_'+this.myid);
        if(title) {
            var title_text = title.value.trim();
            // maximium 64 chars
            if(title_text.length>64) {
                var err_setting = {
                    type:'error', 
                    position:'before', 
                    addTo: this.settingsBox.getElement('table')
                }
                showErrorMessage.bind(this)(tm_lang.label("title_too_many_char"), err_setting);
                return ;
            }
            if(title_text) { 
                // html encode
                this.options.title = htmlentities(title_text);
            } else { 
                // empty title will become as default title
                var default_title = (this.widgetResourceObj) ? 
                    this.widgetResourceObj.label('title') : this.options.title;
                this.options.title = default_title;
            }
        }
        
        // before save event triggered here
        if(!this.onBeforeSave()) return ;
        
        this.saveData( 
            this.myid, // widget id
            JSON.encode( this.makeSettings() ), // settings
            {
                onSuccess: this.sendDataCallBack.bind(this),
                onFailure: this.sendDataCallBackFailure.bind(this)
            } // call backs
        );
    },
    
    // To be defined in module.js
    onBeforeSave: function() { return true;},
    
    makeSettings: function ()
    {
        // Can be overwrite by module.js
        var defaultSetting = JSON.decode(this.defaultSetting);
        var ret = {};
        $each(defaultSetting, function(v, k) {
            if(k=='title') {
                ret[k] = this.options.title ;
            }
            ret[k] = this[k];
        }.bind(this));
        if(this.DEBUG) { this.PrintVar(ret,'makeSettings()-> Saving value');}
        return ret;
    },

    onTimeOut: function(ajaxobject) {
        if (!$chk(ajaxobject)) return;
        var where = ajaxobject.options.parameter;
        this.callbackreadyarray[where] = 1;
        this.callbackcounter++;
        this.updateErrorMessageHash(ajaxobject, wfc_timeout_errorcode);
        g_serverlist.updateLastCheck(ajaxobject.options.parameter2, 0);
    },

    onFail: function(ajaxobject) {
        if (!$chk(ajaxobject)) return;
        if (ajaxobject.isTimeout == true) {
            this.onTimeOut.bind(this)(ajaxobject);
            return;
        }
        var where = ajaxobject.options.parameter;
        this.callbackreadyarray[where] = 1;
        this.callbackcounter++;
        this.updateErrorMessageHash(ajaxobject, wfc_failure_errorcode);
        g_serverlist.updateLastCheck(ajaxobject.options.parameter2, 0);
    },

    updateLastCheck: function(widget, widgetResourceObj) {
        if (this.lastCheck) {
            Element.remove(this.lastCheck);
            this.lastCheck = null;
        }
        if (this.messageBox) this.lastCheck = new Element('div', {
            'class': 'settings_section'
        }).inject(this.messageBox, 'after');
        else this.lastCheck = new Element('div', {
            'class': 'settings_section'
        }).inject(this.settingsBox, 'after');

        var DateObj = new Date();
        this.lastCheck.setHTML('<span style="float:right">' + widgetResourceObj.label(widget + "_lastcheck") + DateObj.formatDate(widgetResourceObj.label(widget + "_dateformat")) + '</span>');
    },

    EditChart: function() {
        if(!this.DEBUG_CHART) return ;
        if($('edit_chart')) 
        {
            var ed = $('edit_chart');
        }
        else
        {
            var ed = new Element('div',{'id':'edit_chart'}).injectInside(document.body);
            var input = new Element('textarea',{'cols':'64','rows':'13'}).injectInside(ed);
            input.value = this.strXML;
            var btn   = new Element('input', {'type':'button','value':'Update Chart'}).addEvent('click', function(){
                var data = $('edit_chart').getElement('textarea').value;
                this.strXML = data;
                this.DrawChart();
            }.bind(this)).injectInside(ed);
            new Element('input', {'type':'button','value':'Hide Editor'}).addEvent('click', function(e){
                var text = $('edit_chart').getElement('textarea');
                var isHidden = (text.getStyle('display')=='none');
                var label = isHidden ? 'Hide Editor':'Show Editor';
                var disp  = isHidden ? '':'none';
                e.target.setAttribute('value', label);
                text.setStyle('display', disp);
            }.bind(this)).injectInside(ed);
        }
    },
        
    sendDataCallBackFailure: function (requestObj) {
		if (!$chk(requestObj)) return;
		this.isAjaxing = false;
        if (requestObj.isTimeout == true) {
			showErrorMessage.bind(this)(this.widgetResourceObj.label(this.options.widgetname+"_save_setting_failed") + "<BR>" + this.widgetResourceObj.label(this.options.widgetname+"_timeout_connect"), this.settingMessageOption);
			return;
		}
		showErrorMessage.bind(this)(this.widgetResourceObj.label(this.options.widgetname+"_save_setting_failed") + "<BR>" + this.widgetResourceObj.label(this.options.widgetname+"_failure_connect"), this.settingMessageOption);
	},

	sendDataCallBack: function (responseObj) {
        var jsonObj = responseObj[1]; 
        this.isAjaxing = false;
        if (jsonObj.errcode != 0) {
            showErrorMessage.bind(this)(this.widgetResourceObj.label(this.options.widgetname+"_save_setting_failed") + "<BR>" + lang.label("errorcode_" + jsonObj.errcode),this.settingMessageOption);
        }
        else {
            if (this.messageBox) {	
                $each(this.boxObject.getElements('div.messageBox'),function(item, key) {
                    Element.remove(item);
                });
                this.messageBox = null;
            }
            //this.reportserver = this.list;
            this.currentscanservercount = this.listcount;
            //DisableSettingComponents.bind(this)();
            this.fillTitle(this.options.title)
            var title = $('widget_title_'+this.myid);
            if (title) {
                title.value = this.options.title;
            }
            
            if (this.settingsBox.style.display != 'none') {
                // close editing box
               if(!custom_options.use_modal_widget_setting)
               {
                $(this.BtnEditID).fireEvent('click', this);
               }
            }
            
            // close the modal settings box
            if(custom_options.use_modal_widget_setting && this.widgetSetting) {
                if(this.widgetSetting.settingBox) {
                    this.widgetSetting.closeModal();
                }
            }
            
            // show widget
            this.ShowWidget();
        }
		
	},
    
    DrawTable: function(w,h) 
    {
        if(!w || !h) {
            var w = this.swfWidth;
            var h = this.swfHeight;
        }
        var parent = this.dataViewBox;
        
        // if table doesn't exist then draw it
        if(!parent.getElement('table')) {
            this.ClearCharts();
            this.MakeTable();
        }
        
        
        // Doing stuffs for redraw/resize table
        this.AdjustTable();
    },
    
    AdjustTable: function()
    {
        // table is existing, so it's re-drawing
        // we need to re-size the table width
        var content = this.contentBlock;
        var table = this.dataViewBox.getElement('table');
        if(table) {
            if(content.getScrollSize().y > content.getSize().y) {
                var w_table = this.contentwidth-17;
                table.setStyle('width', w_table + 'px');
            } else {
                // if table has no scroll bar, give it a bottom border
                table.setStyle('border-bottom', '1px solid #999999');
            }
        }

        // Fix display issue if no flash player
        if(Browser.Plugins.Flash.version<8) {
            this.dataViewBox.setStyles({
                'width'   : '',
                'margin'  : ''
            });
        }
    },
    
    SetLoadingText: function(txt)
    { 
        this.dataViewBox.setHTML('<div class="on_loading">'+txt+'</div>');
    },
    
    InsertContent: function(c) {
        this.dataViewBox.setHTML(c);
    },
    
    ShowWidget: function() 
    {
        if(this.isAjaxing) return ;
        this.isAjaxing = true;
        
        this.SetLoadingText(lang.label('msg_loading'));
        //here will return default parameter for request data
        var requestinfo = (this.GetProxyParameter) ? this.GetProxyParameter() : 
            {   // This is only default parameter, usually widgets has their owns
                module:this.widgetModule,
                serverid:1,
                WID:this.myid,
                SELECTION: (this.reportserver == '#all' ? 0:1),
                T: this.widget_type,
                G: this.groupview,
                D: this.recentdays
            };
        
        wfc_ProxyObj.fetch( 
            requestinfo,
            (this.FAKE_XML?{useJSON:false, async:true, serverCGI:this.FAKE_XML, method:'get'}:{useJSON:false, async:true}), 
            {
                onSuccess: this.RetrieveData.bind(this),
                onFailure: this.onFail.bind(this)
            }
        );
        if(this.DEBUG) { this.PrintVar(wfc_ProxyObj.options.serverCGI , 'ShowWidge()->Ruquest URI');}
        if(this.DEBUG) { this.PrintVar(requestinfo, 'ShowWidge()->requestinfo');}
        if(this.FAKE_XML) {
            wfc_ProxyObj.options.serverCGI = wfc_servercgi_proxyrequest;
        }
    },
    
    /**
     * Draw or redraw the widget table/chart after retrieved data or window resized.
     * Normally you don't need to modified this function.
     * @param {Boolean} NeedToUpdateWidth If needs to update the widget width
     */
    onRedraw: function(NeedToUpdateWidth) 
    {
        this.ResizeElements();
        if ((typeof NeedToUpdateWidth) != 'boolean') NeedToUpdateWidth = false;
		if (NeedToUpdateWidth) {
			if (!this.hasDrawed) return;
		}
        this.AdjustContentHeight();
        var chart_id = 'chart_id' + this.myid ;
        var w = this.swfWidth;
        var h = this.swfHeight;
        
        this.BeforeChart();
        var ifCustom = this.CustomDraw(chart_id, w, h);
        if(!ifCustom) {
            // draw table
            var view_type = this.viewData[this.fushionview];
            if(!view_type || view_type.name=='tabular' ) {
                this.DrawTable(w,h);
                this.parent(NeedToUpdateWidth);
                return ;
            }
            
            // draw charts
            var swf = view_type.swf;
            this.RenderFlash(swf, w, h);
        }
        this.parent(NeedToUpdateWidth);
    },
    
    /**
     * To display your own chart or content, you need to define this function.<br>
     * This fucntion will be called in this.onRedraw(). <br>
     * True should be returned if useing this.CustomDraw()
     * @param {String} chart_id The ID of chart element
     * @param {Number} w The width of content
     * @param {Number} h The height of content
     */ 
    CustomDraw: function(chart_id, w, h)
    {
        // write your own code here
        
        // has to return true if customized content
        return false;
    },
    
    BeforeChart: function()
    {
        this.contentBlock.removeClass('tabular').removeClass('chart');
    },
    
    /** For creating a simple bar chart */
    BarChart: function(chart_id, w, h)
    {
        // draw bar chart
        var swf = 'Bar2D.swf';
        if(!w || !h) {
            var w = this.swfWidth;
            var h = this.swfHeight;
        }
        this.RenderFlash(swf, w, h);
    },
    
    /** For creating a simple pie chart */
    PieChart: function(chart_id, w, h)
    {
        // draw bar chart
        var swf = 'Pie3D.swf';
        if(!w || !h) {
            var w = this.swfWidth;
            var h = this.swfHeight;
        }
        this.RenderFlash(swf, w, h);
    },
    
    /** For creating a simple line chart */
    LineChart: function(chart_id, w, h)
    {
        var swf = 'Line.swf';
        if(!w || !h) {
            var w = this.swfWidth;
            var h = this.swfHeight;
        }
        this.RenderFlash(swf, w, h);
    },
    
    RetrieveData: function(request, data, ajaxobject) 
    {
        this.isAjaxing = false;
        this.strXML = this.ParseXML(data);
        this.xmlData = data;
        if($defined(this.onData)) {
            this.onData(request, data, ajaxobject);
        }
        if(this.DEBUG) { 
            this.PrintVar(this.strXML,'RetrieveData()-> XML String');
        }
        this.EditChart();
        this.UpdateDate(data);
        this.LastCheckTime();
        this.DrawChart();
    },
    
    DrawChart: function() 
    {	   
        this.onRedraw(false);
        this.hasDrawed = true;
    },
    
    /** Called when detecing lack of flash player */
    FlashPlayerNeeded: function(w,h) 
    {
        this.dataViewBox.setStyles({
            'width'   : w+'px',
            'height'  : 'auto',
            'margin'  : '10px auto 0px auto'
        });
        
        this.dataViewBox.setHTML(TM_Lang.label('requirelatest_flash'));
        var link = new Element('a', {'herf':'javascript:void(0);', 'target':'_blank'}).addEvent('click', function(e){
            var w = window.open(TM_Lang.label('flashplayerlink'), this.target).focus();
            if(w) w.focus();
            e.preventDefault();
        }).setHTML(' <u>'+TM_Lang.label('flashplayer')+'</u>').injectInside(this.dataViewBox);
    },
    
    /** The actual step to render fushion chart
     * @param {String} swf File name of SWF
     * @param {Number} w Width of SWF
     * @param {Number} h Height of SWF
     * @param {String} [xml] XML source
     * @param {Object} [parent] Target parent
     */
    RenderFlash: function(swf, w, h, xml, parent) 
    {
        var target = parent||this.dataViewBox;
        target.addClass('chart');
        
        var myChart = new FusionCharts('./lib/FusionCharts/Charts/'+swf, 'chart_id' + this.myid , w , h , '0', '0');
        
        // Workaround for an issue of onloading widget page
        // Sometimes in IE, there's no XML data passed here, we have to re-show widget
        if(!xml && !this.strXML) { 
            return this.ShowWidget();
        };
        myChart.setDataXML(xml||this.strXML);
        myChart.setTransparent(true);
        if(!myChart.render(target))
        {
            this.FlashPlayerNeeded(w,h);
            return false;
        }
        return true;
    },
    
     /**
      * Parse XML string for customized usage
      * @return {XMLObeject} data The XML object
      */
    ParseXML: function(data) 
    {
        var xml  = new StringBuffer();
        var sets = data.getElementsByTagName('set');
        var len  = sets.length;
        
        xml.append('<?xml version="1.0" encoding="UTF-8"?>');
        xml.append('<chart');
        
        // Flash Chart Settings
        xml.append(this.ParseFlashSettings(data));
        xml.append('>');
        
        // data sets
        for(var i=0; i<len; i++) {
            var set = sets[i];
            var link = set.getAttribute('link');
            var percent = set.getAttribute('percent')? (' percent="'+set.getAttribute('percent')+'"') : '';
            xml.append('<set label="'+ htmlentities(set.getAttribute('label')) +'"  value="'
                + htmlentities(set.getAttribute('value')) +'" link="'+ (link?htmlentities(link):'') +'"'+percent+'/>');
        }
        xml.append('</chart>');
        
        return xml.toString();
    },
    
    /** Get flash settings from both XML and widget object
     * Settings of widget object will overwrite XML's 
     * @return {XMLObject} data The data object of XML 
     */
    ParseFlashSettings: function(data)
    {
        var chart = data.getElementsByTagName('chart')[0];
        if(!chart) return '';
        
        var attrs = chart.attributes||[];
        var settings = {};
        var str = '';
        for(var i=attrs.length-1; i>=0; i--) {
            if(attrs[i].nodeName && attrs[i].nodeValue) {
                settings[attrs[i].nodeName] = attrs[i].nodeValue;
            }
        }
        if(this.flashSetting) {
            $extend(settings , this.flashSetting);
        } 
        $each(settings, function(v, i) {
            str += ' '+ i +'="'+ v +'"';
        });
        return str;
    },
    
    /** Method of making basic setting HTML*/
    MakeSettingBlock: function()
    {
        this.settingsBox = new Element('div', {
            'id': 'hmain_settings'+this.myid,
            'class': 'window_setting'
        });
        
    },
    
    MakeContentBlock: function()
    {
        // setting block
        this.MakeSettingBlock();
        
        // message block
        this.messageBlock = new Element('div', {
            'class': 'window1'
        }).injectInside(this.contentBox);
        
        // content block
        this.contentBlock = new Element('div', {
            'id': this.div_id,
            'class': 'window1'
        }).injectInside(this.contentBox);
        
        // last check time
        if(this.hasLastCheckTime) {         
            this.lastCheckBox = new Element('div', {'class':'last_check_time'}).injectInside(this.contentBlock);
        }
        
        // make data view box
        this.dataViewBox = new Element('div', {'class':'data_view'}).injectInside(this.contentBlock).setHTML();
        
        // this.messageBlock.setHTML(lang.label('msg_getsetting'));
        
        this.boxObject.getElement('.btn_close').addEvent('click', this.dialogcancel.bind(this));
        
        this.boxObject.addEvents({
            'BeforeRemoveTab': function() {
                this.dialogcancel();
            }.bind(this)
        });
    },
    
    AdjustContentHeight: function()
    {
        // avoid early calling this function
        if(!this.contentBlock) return ; 
        
        var isTableLayout = wfc_is_table_layout_style(currTabLayout);
        var cell = this.boxObject.getParent();
        var content = this.contentBlock;
        var available_height = this.contentBox.getSize().y;
        var fix = available_height-1;
        var box  = this.boxObject;
        var pos  = content.getCoordinates(this.contentBox);
        /*
        var foot = box.getElement('.window_footer');
        var foot_height    = foot.getSize().y;
        var total_height   = box.getSize().y;
        var content_height = pos.height;
        var box_border     = parseInt(box.getStyle('border-width'), 10);
        var margin_bottom  = parseInt(box.getStyle('margin-bottom'), 10);
        */
        var top = pos.top;
        var scroll = content.getScroll().y
        var new_h = fix - top - scroll;
        
        content.setStyle('height', new_h + 'px');
        content.setStyle('overflow', 'auto');
        // set width/height for swf
        var vbox = this.dataViewBox;
        var pos = vbox.getCoordinates(content);
        var top = pos.top;
        var haveScrollbar  = (new_h - top)<wfc_chart_minheight;
        this.swfWidth  = haveScrollbar ? (this.contentwidth-17):this.contentwidth; 
        this.swfHeight = haveScrollbar ? wfc_chart_minheight: (new_h - top - scroll-2);
        
        return ;
    },
    
    /** For debug 
     * @param {Object||String} data The data to be displayed
     * @param {String} [name] The name to be displayed
     */
    PrintVar: function(data,name) {
        var r = name ? (name+':\n'):'';
        if($type(data)=='string') {
            r += data;
        } else {
            $each(data, function(v, k) {
                r += k +'='+ v +',';
            });
        }
        console.log(r);
    },
    
    AfterDrop: function(src, dst) {
        this.parent(src, dst);
    }
});


/**
 * Use for map type widgets.
 * @class 
 * @constructor
 * @extends tmBoxWindow
 */
 var mapBoxWindow = new Class(
 /** @lends mapBoxWindow */
 {
	Extends:tmBoxWindow,
    /** Map setting */
    mapOptions: {
        path:    './lib/AMMap/',
        swf :    './lib/AMMap/ammap.swf',
        data_file :     './lib/AMMap/world_data.xml',
        settings_file : './lib/AMMap/ammap_settings.xml'
    },
    
    /** Render map function to write actual HTML for Flash */
    RenderMap: function(w, h)
    {
        var options = this.mapOptions;
        var so = new SWFObject(options.swf, 'ammap_'+ this.myid, w, h, '8', '#F0F0F0');
        so.addVariable('path', options.path);
        so.addVariable('settings_file'  , escape(options.settings_file));		
        so.addVariable('map_data' , escape(this.mapXMLString));
        so.addVariable('preloader_color', '#999999');
        so.addParam('wmode', 'transparent');
        so.write(this.dataViewBox);
    },
    
    /** Send ajax to get XML of world map */
    GetMapXML: function()
    {
        // if map data is existing then just redraw 
        if(this.mapData) { this.onRedraw(false); }
        
        // else load world map data
        var mapRequest = new Request({
            url: this.mapOptions.data_file, 
            method: 'get', 
            async:true,
            onSuccess: this.ParseMapXML.bind(this),
            onFailure: this.onFail.bind(this)
        });
        mapRequest.send();
    },
    
    /** parse map XML with backend data */
    ParseMapXML: function(request, mapData, ajaxobject) 
    {
        // prepare the set data array
        var sets = this.xmlData.getElementsByTagName('set');
        var len = sets.length;
        var arr = [];
        while(len) {
            var set = sets[len-1];
            arr[set.getAttribute('country')] = set.getAttribute('value');
            len--;
        }
        
        // set xml meta string
        var xml = [];
        xml.push('<?xml version="1.0" encoding="UTF-8"?><map map_file="maps/world.swf" tl_long="-168.49" tl_lat="83.63" br_long="190.3" br_lat="-55.58" zoom_x="0%" zoom_y="0%" zoom="100%"><areas>');
        
        // inject set data into map data
        var areas = mapData.getElementsByTagName('area');
        var len = areas.length - 1
        while(len) {
            var area = areas[len-1];
            var mc = area.getAttribute('mc_name');
            var t = area.getAttribute('title');
            var v = '';
            if( typeof(arr[mc]) != 'undefined' ) {
                v = ' value="'+ arr[mc] +'"';
            }
            xml.push('<area title="', t,'" mc_name="', mc,'"', v,' />');
            len--;
        }
        
        this.mapData = mapData;
        this.mapXMLString = xml.join('');
        this.DrawChart();
    }
 });